home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / mailconf / complex.c < prev    next >
C/C++ Source or Header  |  1996-07-22  |  8KB  |  333 lines

  1. /* #Specification: mailconf / complex user routing / strategy
  2.     The /etc/aliases mecanims allows one to redirect email to another user
  3.     once it is knows that the email is for this user on this system.
  4.  
  5.     The /var/lib/mailertable mecanism allows one to redirect email for
  6.     a complete domain to another email server.
  7.  
  8.     The complex user routing is a special case allowing you to redirect
  9.     email based on user name and domain name. This was created for
  10.     ISP hosting virtual domain both for WWW and email. This mecanism can
  11.     differentiate between info@virtual1.com and info@virtual2.com.
  12.  
  13.     This capability is achieved by generating sendmail.cf rules directly.
  14. */
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include "mailconf.h"
  18. #include "internal.h"
  19. #include "mailconf.m"
  20.  
  21. static MAILCONF_HELP_FILE help_cplx ("complex");
  22.  
  23. PUBLIC COMPLEX_ROUTE::COMPLEX_ROUTE(
  24.     const char *buf)
  25. {
  26.     SSTRING act;
  27.     buf = str_extract (buf,act);
  28.     active = act.getval();
  29.     buf = str_extract (buf,from);
  30.     buf = str_extract (buf,to);
  31.     buf = str_extract (buf,new_from);
  32.     buf = str_extract (buf,new_to);
  33.     buf = str_extract (buf,router);
  34.     buf = str_extract (buf,mailer);
  35.     buf = str_extract (buf,comment);
  36. }
  37.  
  38. PUBLIC COMPLEX_ROUTE::COMPLEX_ROUTE()
  39. {
  40.     active = 1;
  41.     mailer.setfrom ("esmtp");
  42. }
  43.  
  44. /*
  45.     Edit one rule, return 0 if the edit was successful
  46.     return 1 if this record should be deleted.
  47. */
  48. PUBLIC int COMPLEX_ROUTE::edit()
  49. {
  50.     int ret = -1;
  51.     DIALOG dia;
  52.     dia.newf_chk ("",active,MSG_U(F_CPLXACTIVE,"This rule is active"));
  53.     //dia.newf_str (MSG_U(F_FROM,"from (opt)"),from);
  54.     dia.newf_str (MSG_U(F_TO,"to"),to);
  55.     //dia.newf_str (MSG_U(F_NEWFROM,"new from (opt)"),new_from);
  56.     dia.newf_str (MSG_U(F_NEWTO,"rewriten to"),new_to);
  57.     dia.newf_str (MSG_U(F_ROUTER,"Forward to server(opt)"),router);
  58.     FIELD_COMBO *comb = dia.newf_combo (MSG_R(F_MAILER),mailer);
  59.     dia.newf_str (MSG_U(F_COMMENT,"Comment"),comment);
  60.  
  61.     dia.delwhat (MSG_U(F_DELCPLX,"delete the record"));
  62.     basic_setmailer (comb);
  63.     int nof = 0;
  64.     while (1){
  65.         char buf[100];
  66.         if (to.is_empty()){
  67.             strcpy (buf,MSG_U(T_NEWCOMPLEXROUTE,"New complex route"));
  68.         }else{    
  69.             sprintf (buf,MSG_U(T_COMPLEXROUTE,"complex routing for %s")
  70.                 ,to.get());
  71.         }
  72.         MENU_STATUS code = dia.edit (buf
  73.             ,MSG_U(I_COMPLEXROUTE
  74.             ,"You are allowed to intercept email going to a user\n"
  75.              "and redirect this to a new mail server,\n"
  76.              "using a different protocol.\n"
  77.              "In the process, you can rewrite the TO field\n"
  78.              "and even the from field\n")
  79.             ,help_cplx
  80.             ,nof
  81.             ,MENUBUT_DEL|MENUBUT_ACCEPT|MENUBUT_CANCEL);
  82.         if (code == MENU_CANCEL || code == MENU_ESCAPE){
  83.             dia.restore();
  84.             break;
  85.         }else if (code == MENU_DEL){
  86.             ret = 1;
  87.             break;
  88.         }else{
  89.             char status[2000];
  90.             if (rule0(NULL,status)==-1){
  91.                 xconf_error ("%s",status);
  92.             }else{
  93.                 ret = 0;
  94.                 break;
  95.             }
  96.         }
  97.     }
  98.     return ret;
  99. }
  100.                 
  101.  
  102. static const char CPLXMAIL[]="cplxmail";
  103. static const char CASES[]="cases";
  104.  
  105.  
  106.  
  107. PUBLIC COMPLEX_ROUTES::COMPLEX_ROUTES()
  108. {
  109.     SSTRINGS strs;
  110.     int nb = linuxconf_getall (CPLXMAIL,CASES,strs,0);
  111.     for (int i=0; i<nb; i++){
  112.         add (new COMPLEX_ROUTE(strs.getitem(i)->get()));
  113.     }
  114.     rstmodified();
  115. }
  116.  
  117. PUBLIC COMPLEX_ROUTE *COMPLEX_ROUTES::getitem(int no)
  118. {
  119.     return (COMPLEX_ROUTE*)ARRAY::getitem(no);
  120. }
  121.  
  122. PUBLIC void COMPLEX_ROUTES::save()
  123. {
  124.     linuxconf_removeall (CPLXMAIL,CASES);
  125.     int n = getnb();
  126.     for (int i=0; i<n; i++){
  127.         COMPLEX_ROUTE *c = getitem(i);
  128.         char buf[1000];
  129.         sprintf (buf,"%d \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\""
  130.             ,c->active
  131.             ,c->from.get(),c->to.get()
  132.             ,c->new_from.get(),c->new_to.get()
  133.             ,c->router.get(),c->mailer.get()
  134.             ,c->comment.get());
  135.         linuxconf_add (CPLXMAIL,CASES,buf);
  136.     }
  137.     if (linuxconf_save()!=-1){
  138.         rstmodified();
  139.     }
  140. }
  141.  
  142. static int cmp_by_to (const ARRAY_OBJ *p1, const ARRAY_OBJ *p2)
  143. {
  144.     COMPLEX_ROUTE *r1 = (COMPLEX_ROUTE*)p1;
  145.     COMPLEX_ROUTE *r2 = (COMPLEX_ROUTE*)p2;
  146.     int ret = r1->to.cmp(r2->to);
  147.     if (ret == 0) ret = r1->from.cmp(r2->from);
  148.     return ret;
  149. }
  150.  
  151. PUBLIC int COMPLEX_ROUTES::edit()
  152. {
  153.     int ret = 0;
  154.     int nof = 0;
  155.     while (1){
  156.         sort(cmp_by_to);
  157.         DIALOG dia;
  158.         int n = getnb();
  159.         for (int i=0; i<n; i++){
  160.             COMPLEX_ROUTE *cp = getitem(i);
  161.             dia.new_menuitem (cp->to,cp->new_to);
  162.         }
  163.         dia.addwhat (MSG_U(T_ADDCPLX,"A complex routing rule"));
  164.         MENU_STATUS code = dia.editmenu (MSG_U(T_COMPLEXROUTES,"Complex routings")
  165.             ,MSG_U(I_COMPLEXROUTES
  166.             ,"You can setup multiple complex routing for email\n"
  167.              "The key is the destination, including the user name\n")
  168.             ,help_cplx
  169.             ,nof
  170.             ,MENUBUT_ADD);
  171.         if (code == MENU_QUIT || code == MENU_ESCAPE){
  172.             break;
  173.         }else if (code == MENU_OK){
  174.             if (nof >=0 && nof < n){
  175.                 COMPLEX_ROUTE *cp = getitem(nof);
  176.                 int status = cp->edit();
  177.                 if (status==1){
  178.                     remove_del(cp);
  179.                 }else if (status == 0){
  180.                     save();
  181.                     ret = 1;
  182.                 }
  183.             }
  184.         }else if (code == MENU_ADD){
  185.             COMPLEX_ROUTE *cp = new COMPLEX_ROUTE;
  186.             if (cp->edit()==0){
  187.                 add (cp);
  188.                 save();
  189.                 ret = 1;
  190.             }else{
  191.                 delete cp;
  192.             }
  193.         }
  194.     }
  195.     return ret;
  196. }
  197.  
  198. /*
  199.     Return != 0 if some entry were modified
  200. */
  201. int complex_edit ()
  202. {
  203.     COMPLEX_ROUTES cpl;
  204.     return cpl.edit();
  205. }
  206.  
  207. /*
  208.     Split and validate an addres of the form user@domain
  209. */
  210. static int complex_parse (
  211.     const SSTRING &adr,
  212.     char *user,
  213.     char *site)
  214. {
  215.     int ret = -1;
  216.     char buf[200];
  217.     adr.copy (buf);
  218.     user[0] = site[0] = '\0';
  219.     char *pt = strchr (buf,'@');
  220.     if (pt != NULL){
  221.         *pt++ = '\0';
  222.         strcpy (user,buf);
  223.         strcpy (site,pt);
  224.         ret = 0;
  225.     }
  226.     return ret;
  227. }
  228.  
  229. /*
  230.     Generate the rules to be insert in the ruleset 0 of sendmail.cf.
  231.     if fout == NULL, this function is simply called to validate the
  232.     rule.
  233. */
  234. PUBLIC int COMPLEX_ROUTE::rule0(FILE *fout, char *status)
  235. {
  236.     /* #Specification: mailconf / complex user routing / inactive
  237.         An inactive rule is not validated. This means the user may
  238.         left a rules half finished.
  239.     */
  240.     int ret = 0;
  241.     status[0] = '\0';
  242.     if (active){
  243.         ret = 0;
  244.         char userto[200],siteto[200];
  245.         userto[0] = siteto[0] = '\0';
  246.         if (to.is_empty()){
  247.             status += sprintf (status
  248.                 ,MSG_U(F_NOEMPTY,"Field \"%s\" can't be empty\n")
  249.                 ,MSG_R(F_TO));
  250.             ret = -1;
  251.         }else if (complex_parse (to,userto,siteto) == -1){
  252.             ret = -1;
  253.             status += sprintf (status
  254.                 ,MSG_U(F_IVLDTO,"Field \"%s\" is invalid or incomplete\n"
  255.                     "    Was expecting user@domain format\n")
  256.                 ,MSG_R(F_TO));
  257.         }
  258.         char new_userto[200],new_siteto[200];
  259.         new_userto[0] = new_siteto[0] = '\0';
  260.         int localhost = 0;
  261.         if (new_to.is_empty()){
  262.             status += sprintf (status
  263.                 ,MSG_R(F_NOEMPTY)
  264.                 ,MSG_R(F_NEWTO));
  265.             ret = -1;
  266.         }else if (new_to.strchr('@')==NULL){
  267.             /* #Specification: mailconf / complex routing / new to no site
  268.                 If the "rewritten to" field only contain a name (without @)
  269.                 it is taken as a local user name. This is especially useful
  270.                 when hosting virtual domain and you have the setup
  271.  
  272.                 #
  273.                     info@virtual1.com -> info1
  274.                     info@virtual2.com -> joewho
  275.                 #
  276.             */
  277.             localhost = 1;
  278.             new_to.copy (new_userto);
  279.         }else if (complex_parse (new_to,new_userto,new_siteto)==-1){
  280.             ret = -1;
  281.             status += sprintf (status,MSG_R(F_IVLDTO),MSG_R(F_NEWTO));
  282.         }
  283.         char str_router[200];
  284.         if (router.is_empty()){
  285.             strcpy (str_router,new_siteto);
  286.         }else{
  287.             router.copy(str_router);
  288.         }
  289.         if (!localhost && mailer.is_empty()){
  290.             status += sprintf (status
  291.                 ,MSG_R(F_NOEMPTY)
  292.                 ,MSG_R(F_MAILER));
  293.             ret = -1;
  294.         }
  295.         if (fout != NULL && ret == 0){
  296.             char *pt = "";
  297.             // Another rule in case the domain is qualified by the dns
  298.             // and a . has been added.
  299.             for (int i=0; i<2; i++, pt = "."){
  300.                 if (localhost){
  301.                     fprintf (fout,"R%s<@%s%s>\t$#local $: @ %s\n"
  302.                         ,userto,siteto,pt
  303.                         ,new_userto);
  304.                 
  305.                 }else{
  306.                     fprintf (fout,"R%s<@%s%s>\t$#%s $@%s $: %s < @ %s>\n"
  307.                         ,userto,siteto,pt
  308.                         ,mailer.get(),str_router
  309.                         ,new_userto,new_siteto);
  310.                 }
  311.             }
  312.         }
  313.     }
  314.     return ret;
  315. }
  316.  
  317. /*
  318.     Generate the require parts of ruleset 0.
  319.     Return -1 if any errors.
  320. */
  321. PUBLIC int COMPLEX_ROUTES::rule0(FILE *fout)
  322. {
  323.     int ret = 0;
  324.     int n = getnb();
  325.     for (int i=0; i<n; i++){
  326.         COMPLEX_ROUTE *c = getitem(i);
  327.         char status[10000];
  328.         ret |= c->rule0(fout,status);
  329.     }
  330.     return ret;
  331. }
  332.  
  333.